all repos — caroster @ ce141b018b745094b2e1cec1ceec924ed9bba3f6

[Octree] Group carpool to your event https://caroster.io

frontend/pages/e/[uuid]/details.tsx (view raw)

  1import moment from 'moment';
  2import Button from '@mui/material/Button';
  3import Box from '@mui/material/Box';
  4import Link from '@mui/material/Link';
  5import Paper from '@mui/material/Paper';
  6import Divider from '@mui/material/Divider';
  7import Container from '@mui/material/Container';
  8import TextField from '@mui/material/TextField';
  9import Typography from '@mui/material/Typography';
 10import {useTheme} from '@mui/material/styles';
 11import {DatePicker} from '@mui/x-date-pickers/DatePicker';
 12import {PropsWithChildren, useState} from 'react';
 13import {useTranslation} from 'react-i18next';
 14import pageUtils from '../../../lib/pageUtils';
 15import ShareEvent from '../../../containers/ShareEvent';
 16import useEventStore from '../../../stores/useEventStore';
 17import useToastStore from '../../../stores/useToastStore';
 18import useSettings from '../../../hooks/useSettings';
 19import EventLayout, {TabComponent} from '../../../layouts/Event';
 20import {
 21  EventByUuidDocument,
 22  useUpdateEventMutation,
 23} from '../../../generated/graphql';
 24
 25interface Props {
 26  eventUUID: string;
 27  announcement?: string;
 28}
 29
 30const Page = (props: PropsWithChildren<Props>) => {
 31  return <EventLayout {...props} Tab={DetailsTab} />;
 32};
 33
 34const DetailsTab: TabComponent = ({}) => {
 35  const {t} = useTranslation();
 36  const theme = useTheme();
 37  const settings = useSettings();
 38  const [updateEvent] = useUpdateEventMutation();
 39  const addToast = useToastStore(s => s.addToast);
 40  const setEventUpdate = useEventStore(s => s.setEventUpdate);
 41  const event = useEventStore(s => s.event);
 42  const [isEditing, setIsEditing] = useState(false);
 43  const idPrefix = isEditing ? 'EditEvent' : 'Event';
 44
 45  const onSave = async e => {
 46    try {
 47      const {uuid, ...data} = event;
 48      const {id, travels, waitingPassengers, __typename, ...input} = data;
 49      await updateEvent({
 50        variables: {uuid, eventUpdate: input},
 51        refetchQueries: ['eventByUUID'],
 52      });
 53      setIsEditing(false);
 54    } catch (error) {
 55      console.error(error);
 56      addToast(t('event.errors.cant_update'));
 57    }
 58  };
 59  const sectionSx = {
 60    marginBottom: theme.spacing(2),
 61    width: '540px',
 62    maxWidth: '100%',
 63    paddingX: theme.spacing(2),
 64  };
 65
 66  const modifyButton = isEditing ? (
 67    <Button
 68      variant="contained"
 69      color="primary"
 70      sx={{position: 'absolute', right: theme.spacing(2)}}
 71      onClick={onSave}
 72    >
 73      {t('event.details.save')}
 74    </Button>
 75  ) : (
 76    <Button
 77      variant="text"
 78      color="primary"
 79      sx={{position: 'absolute', right: theme.spacing(2)}}
 80      onClick={() => setIsEditing(true)}
 81    >
 82      {t('event.details.modify')}
 83    </Button>
 84  );
 85
 86  if (!event) return null;
 87
 88  return (
 89    <Box
 90      sx={{
 91        position: 'relative',
 92        paddingLeft: '80px',
 93
 94        [theme.breakpoints.down('md')]: {
 95          paddingLeft: 0,
 96          paddingBottom: '80px',
 97        },
 98      }}
 99    >
100      <Container maxWidth="sm" sx={{marginTop: theme.spacing(6)}}>
101        <Paper sx={{position: 'relative', padding: theme.spacing(2)}}>
102          {modifyButton}
103          <Box sx={sectionSx}>
104            <Typography variant="h6">{t('event.fields.name')}</Typography>
105            {isEditing ? (
106              <TextField
107                fullWidth
108                value={event.name}
109                onChange={e => setEventUpdate({name: e.target.value})}
110                name="name"
111                id="EditEventName"
112              />
113            ) : (
114              <Typography variant="body1" id={`${idPrefix}Name`}>
115                {event.name ?? t('event.fields.empty')}
116              </Typography>
117            )}
118          </Box>
119          <Box sx={sectionSx}>
120            <Typography variant="h6">{t('event.fields.date')}</Typography>
121            {isEditing ? (
122              <DatePicker
123                renderInput={props => (
124                  <TextField
125                    {...props}
126                    id={`${idPrefix}Date`}
127                    fullWidth
128                    placeholder={t('event.fields.date_placeholder')}
129                  />
130                )}
131                value={event.date}
132                onChange={date =>
133                  setEventUpdate({
134                    date: !date ? null : moment(date).format('YYYY-MM-DD'),
135                  })
136                }
137              />
138            ) : (
139              <Typography variant="body1" id={`${idPrefix}Date`}>
140                {event.date
141                  ? moment(event.date).format('DD/MM/YYYY')
142                  : t('event.fields.empty')}
143              </Typography>
144            )}
145          </Box>
146          <Box sx={sectionSx}>
147            <Typography variant="h6">{t('event.fields.address')}</Typography>
148            {isEditing ? (
149              <TextField
150                fullWidth
151                multiline
152                maxRows={4}
153                inputProps={{maxLength: 250}}
154                helperText={`${event.address?.length ?? 0}/250`}
155                defaultValue={event.address}
156                value={event.address}
157                onChange={e => setEventUpdate({address: e.target.value})}
158                id={`${idPrefix}Address`}
159                name="address"
160              />
161            ) : (
162              <Typography variant="body1" id={`${idPrefix}Address`}>
163                {event.address ? (
164                  <Link
165                    target="_blank"
166                    rel="noreferrer"
167                    href={`https://www.google.com/maps/search/?api=1&query=${encodeURIComponent(
168                      event.address
169                    )}`}
170                    onClick={e => e.preventDefault}
171                  >
172                    {event.address}
173                  </Link>
174                ) : (
175                  t('event.fields.empty')
176                )}
177              </Typography>
178            )}
179          </Box>
180          <Box sx={sectionSx}>
181            <Typography variant="h6">
182              {t('event.fields.description')}
183            </Typography>
184            {isEditing ? (
185              <TextField
186                fullWidth
187                multiline
188                maxRows={4}
189                inputProps={{maxLength: 250}}
190                helperText={`${event.description?.length || 0}/250`}
191                defaultValue={event.description}
192                value={event.description || ''}
193                onChange={e => setEventUpdate({description: e.target.value})}
194                id={`${idPrefix}Description`}
195                name="description"
196              />
197            ) : (
198              <Typography variant="body1" id={`${idPrefix}Description`}>
199                {event.description ?? t('event.fields.empty')}
200              </Typography>
201            )}
202          </Box>
203          <Box sx={sectionSx}>
204            <Typography variant="h6">{t('event.fields.link')}</Typography>
205            <Typography>{t('event.fields.link_desc')}</Typography>
206          </Box>
207          <Box py={4} justifyContent="center" display="flex">
208            <ShareEvent
209              title={`Caroster ${event.name}`}
210              url={`${window.location.href}`}
211            />{' '}
212          </Box>
213          <Divider variant="middle" />
214          <Box pt={2} justifyContent="center" display="flex">
215            <Link href={settings?.about_link} target="_blank" rel="noopener">
216              {t('event.details.aboutCaroster')}
217            </Link>
218          </Box>
219        </Paper>
220      </Container>
221    </Box>
222  );
223};
224
225export const getServerSideProps = pageUtils.getServerSideProps(
226  async (context, apolloClient) => {
227    const {uuid} = context.query;
228    const {host = ''} = context.req.headers;
229    let event = null;
230
231    // Fetch event
232    try {
233      const {data} = await apolloClient.query({
234        query: EventByUuidDocument,
235        variables: {uuid},
236      });
237      event = data?.eventByUUID?.data;
238    } catch (error) {
239      return {
240        notFound: true,
241      };
242    }
243
244    return {
245      props: {
246        eventUUID: uuid,
247        metas: {
248          title: event?.attributes?.name || '',
249          url: `https://${host}${context.resolvedUrl}`,
250        },
251      },
252    };
253  }
254);
255export default Page;